import React, { useState, useRef, useEffect, forwardRef } from "react";
import styled from "@emotion/styled";
import { createPortal } from "react-dom";
import { FiChevronDown } from "react-icons/fi";

interface SelectProps
  extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "onChange"> {
  error?: boolean;
  fullWidth?: boolean;
  onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void;
}

export type { SelectProps };

const SelectContainer = styled.div<{
  error?: boolean;
  fullWidth?: boolean;
  $isOpen?: boolean;
}>`
  position: relative;
  width: ${(props) => (props.fullWidth ? "100%" : "auto")};
`;

const SelectTrigger = styled.button<{ error?: boolean; $isOpen?: boolean }>`
  width: 100%;
  padding: 0.625rem 2rem 0.625rem 0.75rem;
  border: 1px solid
    ${(props) =>
      props.error
        ? "var(--error-color, #ef4444)"
        : props.$isOpen
        ? "var(--accent-color, #3b82f6)"
        : "var(--border-color, #e5e7eb)"};
  border-radius: 6px;
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 0.875rem;
  font-family: inherit;
  line-height: 1.5;
  transition: border-color 0.2s ease, background-color 0.2s ease;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 2.5rem;
  text-align: left;
  appearance: none;
  -webkit-appearance: none;

  @media (max-width: 768px) {
    font-size: 15px;
    min-height: 40px;
    padding: 0.5rem 2rem 0.5rem 0.625rem;
  }

  &:hover:not(:disabled) {
    border-color: ${(props) =>
      props.error
        ? "var(--error-color, #ef4444)"
        : "var(--accent-color, #3b82f6)"};
  }

  &:focus {
    outline: none;
    border-color: ${(props) =>
      props.error
        ? "var(--error-color, #ef4444)"
        : "var(--accent-color, #3b82f6)"};
  }

  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background: var(--bg-tertiary);
  }

  svg {
    flex-shrink: 0;
    transition: transform 0.2s ease;
    transform: ${(props) =>
      props.$isOpen ? "rotate(180deg)" : "rotate(0deg)"};
    color: var(--text-secondary);
  }
`;

const DropdownMenu = styled.div<{
  $position: { top: number; left: number; width: number };
}>`
  position: fixed;
  top: ${(props) => props.$position.top}px;
  left: ${(props) => props.$position.left}px;
  width: ${(props) => props.$position.width}px;
  background: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  z-index: 1000;
  max-height: 300px;
  overflow-y: auto;
  margin-top: 4px;

  [data-theme="dark"] & {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  }

  @media (max-width: 768px) {
    max-height: 250px;
  }
`;

const OptionItem = styled.div<{ $selected?: boolean; $disabled?: boolean }>`
  padding: 0.625rem 0.75rem;
  cursor: ${(props) => (props.$disabled ? "not-allowed" : "pointer")};
  color: ${(props) =>
    props.$disabled ? "var(--text-tertiary)" : "var(--text-primary)"};
  font-size: 0.875rem;
  transition: background-color 0.15s ease;
  opacity: ${(props) => (props.$disabled ? 0.5 : 1)};

  &:hover:not([data-disabled="true"]) {
    background: rgba(var(--accent-rgb, 81, 131, 245), 0.08);
  }

  &[data-selected="true"] {
    background: rgba(var(--accent-rgb, 81, 131, 245), 0.12);
    color: var(--accent-color);
    font-weight: 500;
  }

  &:first-of-type {
    border-radius: 6px 6px 0 0;
  }

  &:last-of-type {
    border-radius: 0 0 6px 6px;
  }
`;

const HiddenSelect = styled.select`
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 0;
  height: 0;
`;

const Select = forwardRef<HTMLSelectElement, SelectProps>(
  (
    { children, error, fullWidth = true, value, onChange, disabled, ...props },
    ref
  ) => {
    const [isOpen, setIsOpen] = useState(false);
    const [position, setPosition] = useState({ top: 0, left: 0, width: 0 });
    const containerRef = useRef<HTMLDivElement>(null);
    const triggerRef = useRef<HTMLButtonElement>(null);
    const hiddenSelectRef = useRef<HTMLSelectElement>(null);
    const dropdownRef = useRef<HTMLDivElement>(null);

    const options = React.Children.toArray(children) as React.ReactElement<
      React.OptionHTMLAttributes<HTMLOptionElement>
    >[];

    const selectedOption = options.find(
      (option) =>
        option.props.value === value ||
        option.props.value === hiddenSelectRef.current?.value
    );

    const displayValue =
      selectedOption?.props.children || (value as string) || "";

    const updatePosition = () => {
      if (triggerRef.current) {
        const rect = triggerRef.current.getBoundingClientRect();
        setPosition({
          top: rect.bottom + window.scrollY,
          left: rect.left + window.scrollX,
          width: rect.width,
        });
      }
    };

    useEffect(() => {
      if (isOpen) {
        updatePosition();
        const handleResize = () => updatePosition();
        const handleScroll = () => updatePosition();
        window.addEventListener("resize", handleResize);
        window.addEventListener("scroll", handleScroll, true);
        return () => {
          window.removeEventListener("resize", handleResize);
          window.removeEventListener("scroll", handleScroll, true);
        };
      }
    }, [isOpen]);

    useEffect(() => {
      const handleClickOutside = (e: MouseEvent) => {
        if (
          isOpen &&
          containerRef.current &&
          !containerRef.current.contains(e.target as Node) &&
          dropdownRef.current &&
          !dropdownRef.current.contains(e.target as Node)
        ) {
          setIsOpen(false);
        }
      };

      if (isOpen) {
        document.addEventListener("mousedown", handleClickOutside);
        return () =>
          document.removeEventListener("mousedown", handleClickOutside);
      }
    }, [isOpen]);

    const handleToggle = (e: React.MouseEvent) => {
      e.stopPropagation();
      if (!disabled) {
        setIsOpen(!isOpen);
      }
    };

    const handleSelect = (optionValue: string | number | undefined) => {
      if (!optionValue || disabled) return;

      if (hiddenSelectRef.current) {
        hiddenSelectRef.current.value = String(optionValue);
        const syntheticEvent = {
          target: hiddenSelectRef.current,
          currentTarget: hiddenSelectRef.current,
        } as React.ChangeEvent<HTMLSelectElement>;

        if (onChange) {
          onChange(syntheticEvent);
        }
      }

      setIsOpen(false);
    };

    const handleKeyDown = (e: React.KeyboardEvent) => {
      if (disabled) return;

      if (e.key === "Enter" || e.key === " ") {
        e.preventDefault();
        setIsOpen(!isOpen);
      } else if (e.key === "Escape" && isOpen) {
        setIsOpen(false);
      } else if (isOpen && (e.key === "ArrowDown" || e.key === "ArrowUp")) {
        e.preventDefault();
        const currentIndex = options.findIndex(
          (opt) =>
            opt.props.value === value ||
            opt.props.value === hiddenSelectRef.current?.value
        );
        let nextIndex = currentIndex;

        if (e.key === "ArrowDown") {
          nextIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0;
        } else {
          nextIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1;
        }

        const nextOption = options[nextIndex];
        if (nextOption && !nextOption.props.disabled) {
          handleSelect(nextOption.props.value as string | number);
        }
      }
    };

    React.useImperativeHandle(ref, () => hiddenSelectRef.current!);

    return (
      <>
        <SelectContainer
          ref={containerRef}
          error={error}
          fullWidth={fullWidth}
          $isOpen={isOpen}
        >
          <HiddenSelect
            ref={hiddenSelectRef}
            value={value}
            onChange={onChange}
            disabled={disabled}
            {...props}
          >
            {children}
          </HiddenSelect>
          <SelectTrigger
            ref={triggerRef}
            type="button"
            error={error}
            $isOpen={isOpen}
            disabled={disabled}
            onClick={handleToggle}
            onKeyDown={handleKeyDown}
            aria-haspopup="listbox"
            aria-expanded={isOpen}
          >
            <span>{displayValue || "请选择..."}</span>
            <FiChevronDown size={16} />
          </SelectTrigger>
        </SelectContainer>
        {isOpen &&
          createPortal(
            <DropdownMenu ref={dropdownRef} $position={position}>
              {options.map((option, index) => {
                const optionValue = option.props.value;
                const isSelected =
                  optionValue === value ||
                  optionValue === hiddenSelectRef.current?.value;
                const isDisabled = option.props.disabled;

                return (
                  <OptionItem
                    key={index}
                    $selected={isSelected}
                    $disabled={isDisabled}
                    data-selected={isSelected}
                    data-disabled={isDisabled}
                    onClick={() =>
                      !isDisabled &&
                      handleSelect(optionValue as string | number)
                    }
                    onMouseEnter={(e) => {
                      if (!isDisabled) {
                        e.currentTarget.style.background =
                          "rgba(var(--accent-rgb, 81, 131, 245), 0.08)";
                      }
                    }}
                    onMouseLeave={(e) => {
                      if (!isDisabled) {
                        e.currentTarget.style.background = isSelected
                          ? "rgba(var(--accent-rgb, 81, 131, 245), 0.12)"
                          : "transparent";
                      }
                    }}
                  >
                    {option.props.children}
                  </OptionItem>
                );
              })}
            </DropdownMenu>,
            document.body
          )}
      </>
    );
  }
);

Select.displayName = "Select";

export default Select;
